package com.zisu.secs.secs.hsmsss;

import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousSocketChannel;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeoutException;
import java.util.stream.Collectors;

import com.zisu.secs.secs.AbstractSecsInnerEngine;
import com.zisu.secs.secs.secs2.Secs2;
import com.zisu.secs.secs.secs2.Secs2BytesParser;

public class HsmsSsByteReader extends AbstractSecsInnerEngine implements Callable<Void> {
	
	private final AbstractHsmsSsCommunicator parent;
	private final AsynchronousSocketChannel channel;

	public HsmsSsByteReader(AbstractHsmsSsCommunicator parent, AsynchronousSocketChannel channel) {
		super(parent);
		this.parent = parent;
		this.channel = channel;
	}
	
	
	private static final byte[] emptyBytes = new byte[]{0, 0, 0, 0};
	
	/**
	 * until detect-terminate or Timeout-T8
	 */
	@Override
	public Void call() throws Exception {
		
		try {
			//实际 HSMS lenBf 是4个字节的，这里设置了8个字节，下面有lenBf.put(emptyBytes); put了4个字节，所以剩下就4个字节 是ok的
			final ByteBuffer lenBf = ByteBuffer.allocate(8);
			final ByteBuffer headBf = ByteBuffer.allocate(10);

			//一直循环 从通道上读取数据
			for ( ;; ) {

				((Buffer)lenBf).clear();
				((Buffer)headBf).clear();

				//put了4个字节 ，之后读数据到lenBf 就从第五个字节开始
				lenBf.put(emptyBytes);

				//读取远程 过来 的message
				readToByteBuffer(lenBf, false);

				//hasRemaining()  返回剩余的可用长度
				while ( lenBf.hasRemaining() ) {
					readToByteBuffer(lenBf, true);
				}
				
				while ( headBf.hasRemaining() ) {
					readToByteBuffer(headBf, true);
				}
				
				((Buffer)lenBf).flip();
				//lenBf.getLong() 是整个报文长度 ，减10 就是除了请求体长度。
				long bodyLength = lenBf.getLong() - 10;
				
				if ( bodyLength < 0 ) {
					continue;
				}
				
				BodyReader bodyReader = new BodyReader(this, bodyLength);
				
				while ( ! bodyReader.completed() ) {
					bodyReader.reading();
				}
				
				((Buffer)headBf).flip();
				byte[] head = new byte[10];
				headBf.get(head);
				
				Secs2 body = Secs2BytesParser.getInstance().parse(bodyReader.getByteBuffers());
				HsmsSsMessage msg = parent.createHsmsSsMessage(head, body);

				//这里调用用 HsmsSsMessageReceiveListener接口的receive 方法 。
				// 所有注册到listeners 的HsmsSsMessageReceiveListener 都会收到这个msg
				listeners.forEach(lstnr -> {
					lstnr.receive(msg);
				});
				
				notifyReceiveMessagePassThrough(msg);
				notifyLog("Received HsmsSs-Message", msg);
			}
		}
		catch ( HsmsSsDetectTerminateException | HsmsSsTimeoutT8Exception e ) {
			notifyLog(e);
		}
		catch ( InterruptedException ignore ) {
		}
		
		return null;
	}
	
	
	private int readToByteBuffer(ByteBuffer buffer, boolean detectT8Timeout)
			throws HsmsSsDetectTerminateException, HsmsSsTimeoutT8Exception, InterruptedException {
		//channel 读buffer流 到指定的变量（buffer）里面
		Future<Integer> f = channel.read(buffer);
		
		try {
			int r;
			
			if ( detectT8Timeout ) {
				
				r = parent.hsmsSsConfig().timeout().t8().future(f);
				
			} else {
				
				r = f.get();
			}
			
			if ( r < 0 ) {
				throw new HsmsSsDetectTerminateException();
			}
			
			return r;
		}
		catch ( TimeoutException e ) {
			f.cancel(true);
			throw new HsmsSsTimeoutT8Exception(e);
		}
		catch ( ExecutionException e ) {
			
			Throwable t = e.getCause();
			
			if ( t instanceof RuntimeException ) {
				throw (RuntimeException)t;
			}
			
			if ( t instanceof Error ) {
				throw (Error)t;
			}
			
			throw new HsmsSsDetectTerminateException(e);
		}
		catch ( InterruptedException e ) {
			f.cancel(true);
			throw e;
		}
	}
	
	private static final int bufferSize = 1024;
	
	private class BodyReader {
		
		private final HsmsSsByteReader parent;
		private final long size;
		private long present;
		//这个buffers 就是 ByteBuffer块，，之所以要LinkedList类型就是为了 动态分配内存用的
		private final LinkedList<ByteBuffer> buffers = new LinkedList<>();
		
		public BodyReader(HsmsSsByteReader parent, long size) {
			this.parent = parent;
			this.size = size;
			this.present = 0;
			addBuffer();
		}
		
		private void addBuffer() {
			long i = size - present;
			//如果要读取的数据长度 大于1024 那么先分配1M，	如果还不够那再加
			if ( i > bufferSize ) {
				buffers.add(ByteBuffer.allocate(bufferSize));
			} else {
				buffers.add(ByteBuffer.allocate((int)i));
			}
		}
		
		public void reading()
				throws HsmsSsDetectTerminateException, HsmsSsTimeoutT8Exception
				, InterruptedException {
			
			ByteBuffer bf = buffers.getLast();

			//readToByteBuffer==> 就是把Byte写到bf
			int r = parent.readToByteBuffer(bf, true);
			
			this.present += r;

			//如果bf 没有剩余 容量了，，就懂太分配。
			if ( ! bf.hasRemaining() ) {
				//动态分配内存
				if ( present < size ) {
					addBuffer();
				}
			}

		}
		
		public boolean completed() {
			return present == size;
		}

		//调整 buffers 块 的指针（用flip） 就是读写 转换
		public List<ByteBuffer> getByteBuffers() {

			return buffers.stream()
					.map(bf -> {
						((Buffer)bf).flip();
						return bf;
					})
					.collect(Collectors.toList());
		}
	}
	
	private final Collection<HsmsSsMessageReceiveListener> listeners = new CopyOnWriteArrayList<>();
	
	public boolean addHsmsSsMessageReceiveListener(HsmsSsMessageReceiveListener lstnr) {
		return listeners.add(lstnr);
	}
	
}
